/********************************************************************
	created:	2012/04/08   17:54
	filename: 	hy_bind_handler.h
	author:		supercaco@sina.com
	purpose:	
*********************************************************************/
#ifndef _HY_BIND_HANDLER_H_
#define _HY_BIND_HANDLER_H_

#include "hy_handler_alloc_helpers.h"
#include "hy_handler_invoke.h"

namespace hy {

	// Base class for classes that need a handler data member. Forwards the custom
	// allocation and invocation hooks to the contained handler.
	template <typename Handler>
	class handler_base_from_member
	{
	public:
		handler_base_from_member(Handler handler)
			: handler_(handler){}

		//protected:
		Handler handler_;

	protected:
		// Protected destructor to prevent deletion through this type.
		~handler_base_from_member(){}
	};

	template <typename Handler>
	inline void* hy_handler_allocate(std::size_t size,
		handler_base_from_member<Handler>* this_handler)
	{
		return hy_handler_alloc_helpers::allocate(
			size, &this_handler->handler_);
	}

	template <typename Handler>
	inline void hy_handler_deallocate(void* pointer, std::size_t size,
		handler_base_from_member<Handler>* this_handler)
	{
		hy_handler_alloc_helpers::deallocate(
			pointer, size, &this_handler->handler_);
	}

	template <typename Function, typename Handler>
	inline void hy_handler_invoke(const Function& function,
		handler_base_from_member<Handler>* this_handler)
	{
		hy_handler_invoke_helpers::invoke(
			function, &this_handler->handler_);
	}

	//binder one param
	template <typename Handler, typename Arg1>
	class binder1
	{
	public:
		binder1(const Handler& handler, const Arg1& arg1)
			: handler_(handler),arg1_(arg1)
		{
		}

		void operator()()
		{
			handler_(arg1_);
		}

		void operator()() const
		{
			handler_(arg1_);
		}

		//private:
		Handler handler_;
		Arg1 arg1_;
	};

	template <typename Handler, typename Arg1>
	inline void* hy_handler_allocate(std::size_t size,
		binder1<Handler, Arg1>* this_handler)
	{
		return hy_handler_alloc_helpers::allocate(
			size, &this_handler->handler_);
	}

	template <typename Handler, typename Arg1>
	inline void hy_handler_deallocate(void* pointer, std::size_t size,
		binder1<Handler, Arg1>* this_handler)
	{
		hy_handler_alloc_helpers::deallocate(
			pointer, size, &this_handler->handler_);
	}

	template <typename Function, typename Handler, typename Arg1>
	inline void hy_handler_invoke(const Function& function,
		binder1<Handler, Arg1>* this_handler)
	{
		hy_handler_invoke_helpers::invoke(
			function, &this_handler->handler_);
	}

	template <typename Handler, typename Arg1>
	inline binder1<Handler, Arg1> bind_handler(const Handler& handler,
		const Arg1& arg1)
	{
		return binder1<Handler, Arg1>(handler, arg1);
	}

	//binder two param
	template <typename Handler, typename Arg1, typename Arg2>
	class binder2
	{
	public:
		binder2(const Handler& handler, const Arg1& arg1, const Arg2& arg2)
			: handler_(handler),arg1_(arg1),arg2_(arg2)
		{
		}

		void operator()()
		{
			handler_(arg1_, arg2_);
		}

		void operator()() const
		{
			handler_(arg1_, arg2_);
		}

		//private:
		Handler handler_;
		Arg1 arg1_;
		Arg2 arg2_;
	};

	template <typename Handler, typename Arg1, typename Arg2>
	inline void* hy_handler_allocate(std::size_t size,
		binder2<Handler, Arg1, Arg2>* this_handler)
	{
		return hy_handler_alloc_helpers::allocate(
			size, &this_handler->handler_);
	}

	template <typename Handler, typename Arg1, typename Arg2>
	inline void hy_handler_deallocate(void* pointer, std::size_t size,
		binder2<Handler, Arg1, Arg2>* this_handler)
	{
		hy_handler_alloc_helpers::deallocate(
			pointer, size, &this_handler->handler_);
	}

	template <typename Function, typename Handler, typename Arg1, typename Arg2>
	inline void hy_handler_invoke(const Function& function,
		binder2<Handler, Arg1, Arg2>* this_handler)
	{
		hy_handler_invoke_helpers::invoke(
			function, &this_handler->handler_);
	}

	template <typename Handler, typename Arg1, typename Arg2>
	inline binder2<Handler, Arg1, Arg2> bind_handler(const Handler& handler,
		const Arg1& arg1, const Arg2& arg2)
	{
		return binder2<Handler, Arg1, Arg2>(handler, arg1, arg2);
	}

	//binder three param
	template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
	class binder3
	{
	public:
		binder3(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
			const Arg3& arg3)
			: handler_(handler),
			arg1_(arg1),
			arg2_(arg2),
			arg3_(arg3)
		{
		}

		void operator()()
		{
			handler_(arg1_, arg2_, arg3_);
		}

		void operator()() const
		{
			handler_(arg1_, arg2_, arg3_);
		}

		//private:
		Handler handler_;
		Arg1 arg1_;
		Arg2 arg2_;
		Arg3 arg3_;
	};

	template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
	inline void* hy_handler_allocate(std::size_t size,
		binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
	{
		return hy_handler_alloc_helpers::allocate(
			size, &this_handler->handler_);
	}

	template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
	inline void hy_handler_deallocate(void* pointer, std::size_t size,
		binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
	{
		hy_handler_alloc_helpers::deallocate(
			pointer, size, &this_handler->handler_);
	}

	template <typename Function, typename Handler, typename Arg1, typename Arg2,
		typename Arg3>
		inline void hy_handler_invoke(const Function& function,
		binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
	{
		hy_handler_invoke_helpers::invoke(
			function, &this_handler->handler_);
	}

	template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
	inline binder3<Handler, Arg1, Arg2, Arg3> bind_handler(const Handler& handler,
		const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)
	{
		return binder3<Handler, Arg1, Arg2, Arg3>(handler, arg1, arg2, arg3);
	}

	//binder four param
	template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
		typename Arg4>
	class binder4
	{
	public:
		binder4(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
			const Arg3& arg3, const Arg4& arg4)
			: handler_(handler),
			arg1_(arg1),
			arg2_(arg2),
			arg3_(arg3),
			arg4_(arg4)
		{
		}

		void operator()()
		{
			handler_(arg1_, arg2_, arg3_, arg4_);
		}

		void operator()() const
		{
			handler_(arg1_, arg2_, arg3_, arg4_);
		}

		//private:
		Handler handler_;
		Arg1 arg1_;
		Arg2 arg2_;
		Arg3 arg3_;
		Arg4 arg4_;
	};

	template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
		typename Arg4>
		inline void* hy_handler_allocate(std::size_t size,
		binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
	{
		return hy_handler_alloc_helpers::allocate(
			size, &this_handler->handler_);
	}

	template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
		typename Arg4>
		inline void hy_handler_deallocate(void* pointer, std::size_t size,
		binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
	{
		hy_handler_alloc_helpers::deallocate(
			pointer, size, &this_handler->handler_);
	}

	template <typename Function, typename Handler, typename Arg1, typename Arg2,
		typename Arg3, typename Arg4>
		inline void hy_handler_invoke(const Function& function,
		binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
	{
		hy_handler_invoke_helpers::invoke(
			function, &this_handler->handler_);
	}

	template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
		typename Arg4>
		inline binder4<Handler, Arg1, Arg2, Arg3, Arg4> bind_handler(
		const Handler& handler, const Arg1& arg1, const Arg2& arg2,
		const Arg3& arg3, const Arg4& arg4)
	{
		return binder4<Handler, Arg1, Arg2, Arg3, Arg4>(handler, arg1, arg2, arg3,arg4);
	}

	//binder five param
	template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
		typename Arg4, typename Arg5>
	class binder5
	{
	public:
		binder5(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
			const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
			: handler_(handler),
			arg1_(arg1),
			arg2_(arg2),
			arg3_(arg3),
			arg4_(arg4),
			arg5_(arg5)
		{
		}

		void operator()()
		{
			handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
		}

		void operator()() const
		{
			handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
		}

		//private:
		Handler handler_;
		Arg1 arg1_;
		Arg2 arg2_;
		Arg3 arg3_;
		Arg4 arg4_;
		Arg5 arg5_;
	};

	template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
		typename Arg4, typename Arg5>
		inline void* hy_handler_allocate(std::size_t size,
		binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
	{
		return hy_handler_alloc_helpers::allocate(
			size, &this_handler->handler_);
	}

	template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
		typename Arg4, typename Arg5>
		inline void hy_handler_deallocate(void* pointer, std::size_t size,
		binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
	{
		hy_handler_alloc_helpers::deallocate(
			pointer, size, &this_handler->handler_);
	}

	template <typename Function, typename Handler, typename Arg1, typename Arg2,
		typename Arg3, typename Arg4, typename Arg5>
		inline void hy_handler_invoke(const Function& function,
		binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
	{
		hy_handler_invoke_helpers::invoke(
			function, &this_handler->handler_);
	}

	template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
		typename Arg4, typename Arg5>
		inline binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5> bind_handler(
		const Handler& handler, const Arg1& arg1, const Arg2& arg2,
		const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
	{
		return binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>(handler, arg1, arg2,
			arg3, arg4, arg5);
	}

	//----------------------------------------------------------------------------
	//----------------------- net and thread use   -------------------------------
	//----------------------------------------------------------------------------
	template < typename Handler>
	class callback0
	{
	public:
		callback0(const Handler handler)
			: handler_(handler)
		{
		}

		void operator()()
		{
			handler_();			
		}

		void operator()() const
		{
			handler_();
		}

	private:
		Handler handler_;
	};

	template < typename Handler, typename ArgType>
	class callback1
	{
	public:
		callback1(const Handler handler)
			: handler_(handler)
		{
		}

		void operator()(const ArgType& arg1)
		{
			handler_(arg1);			
		}

		void operator()(const ArgType& arg1) const
		{
			handler_(arg1);
		}

	private:
		Handler handler_;
	};

	template < typename Handler, typename ArgType1, typename ArgType2>
	class callback2
	{
	public:
		callback2(const Handler handler)
			: handler_(handler){}

		void operator()(const ArgType1& arg1,const ArgType2& arg2)
		{
			handler_(arg1,arg2) ;
		}

		void operator()(const ArgType1& arg1,const ArgType2& arg2) const
		{
			handler_(arg1,arg2) ;
		}

	private:
		Handler handler_;
	};

	template < typename Handler, typename ClassType>
	class obj_callback0
	{
	public:
		obj_callback0(Handler handler, ClassType* arg1)
			: handler_(handler),
			Obj_(arg1)
		{
		}

		void operator()()
		{
			(Obj_->*handler_)();
		}

		void operator()() const
		{
			(Obj_->*handler_)();
		}

	private:
		Handler handler_;
		ClassType* Obj_;
	};

	template < typename Handler, typename ClassType, typename ArgType1>
	class obj_callback1
	{
	public:
		obj_callback1(Handler handler, ClassType* arg1)
			: handler_(handler),
			Obj_(arg1)
		{
		}

		void operator()(const ArgType1& arg1)
		{
			(Obj_->*handler_)(arg1);
		}

		void operator()(const ArgType1& arg1) const
		{
			(Obj_->*handler_)(arg1);
		}

	private:
		Handler handler_;
		ClassType* Obj_;
	};

	template < typename Handler, typename ClassType, typename ArgType1, typename ArgType2>
	class obj_callback2
	{
	public:
		obj_callback2(Handler handler, ClassType* arg1)
			: handler_(handler),
			Obj_(arg1)
		{
		}

		void operator()(ArgType1& arg1,ArgType2 arg2)
		{
			(Obj_->*handler_)(arg1,arg2);
		}

		void operator()(ArgType1& arg1,ArgType2 arg2) const
		{
			(Obj_->*handler_)(arg1,arg2);
		}

	private:
		Handler handler_;
		ClassType* Obj_;
	};

	template <typename Handler>
	inline callback0<Handler> bind_th_callback(const Handler handler)
	{
		return callback0<Handler>(handler);
	}
	template <typename Handler, typename Arg1>
	inline obj_callback0<Handler, Arg1> bind_th_callback(
		const Handler handler, Arg1* arg1)
	{
		return obj_callback0<Handler, Arg1>(handler, arg1);
	}


	template <typename Handler>
	inline callback1<Handler, hy_err_t> bind_ct_callback(const Handler handler)
	{
		return callback1<Handler, hy_err_t>(handler);
	}

	template <typename Handler, typename Arg1>
	inline obj_callback1<Handler, Arg1, hy_err_t> bind_ct_callback(
		const Handler handler, Arg1* arg1)
	{
		return obj_callback1<Handler, Arg1, hy_err_t>(handler, arg1);
	}

	template <typename Handler>
	inline callback2<Handler, const hy_err_t, size_t> bind_rs_callback(const Handler handler)
	{
		return callback2<Handler, const hy_err_t, size_t>(handler);
	}

	template <typename Handler, typename Arg1>
		inline obj_callback2<Handler, Arg1, const hy_err_t, size_t> bind_rs_callback(
		const Handler& handler, Arg1* arg1)
	{
		return obj_callback2<Handler, Arg1, const hy_err_t, size_t>(handler, arg1);
	}


} // namespace hy
#endif
